//
// Created by 史振江 on 8/3/23.
//

#include "SAudioChannel.h"

void SAudioChannel::initFaacEncoder(int channel, int sampleRate) {
    pthread_mutex_lock(&mutex);

    this->mChannels = channel;

    // 初始化faac
    // sampleRate 采样率
    // channel 通道数
    // inputSamples 输出样本
    // maxOutputBytes 输出最大输出字节 (用来定义缓存区)
    LOG_D("FAAC 打开编码器")
    audioEncoder = faacEncOpen(sampleRate, channel, &inputSamples, &maxOutputBytes);
    if (!audioEncoder) {
        LOG_D("打开音频编码器失败");
        return;
    }
    LOG_D("FAAC 配置编码器参数")
    /**
    * 第二步：配置编码器参数
    */
    faacEncConfigurationPtr config = faacEncGetCurrentConfiguration(audioEncoder);

    config->mpegVersion = MPEG4; // mpeg4标准 acc音频标准

    config->aacObjectType = LOW; // LC标准： https://zhidao.baidu.com/question/1948794313899470708.html

    config->inputFormat = FAAC_INPUT_16BIT; // 16bit

    // 比特流输出格式为：Raw
    config->outputFormat = 0;

    // 开启降噪
    config->useTns = 1;
    config->useLfe = 0;

    LOG_D("FAAC 设置参数")
    // 设置参数
    faacEncSetConfiguration(audioEncoder, config);


    // 缓存区 (存放压缩后的数据)
    this->buffer = new u_char(maxOutputBytes);

    LOG_D("FAAC 初始化成功")
    pthread_mutex_unlock(&mutex);
}

SAudioChannel::~SAudioChannel() {
    pthread_mutex_destroy(&mutex);
    DELETE(buffer)
    if (audioEncoder)
        faacEncClose(audioEncoder);
}

int SAudioChannel::getInputSample() const {
    return this->inputSamples;
}

void SAudioChannel::getSequenceHeader() {
    RTMPPacket *packet = nullptr;


    // 获取序列头数据
    u_char *charP;
    u_long len;
    faacEncGetDecoderSpecificInfo(audioEncoder, &charP, &len);

    int body_size = 2 + len;
    RTMPPacket_Alloc(packet, body_size);

    packet->m_body[0] = 0XAF; // 双声道
    if (mChannels == 1) {
        packet->m_body[0] = 0XAE; // 单声道
    }

    packet->m_body[1] = 0X00; // 表示是序列头

    memcpy(&packet->m_body[2], charP, len);

    // 将数据copy到pack中
    memcpy(&packet->m_body[2], buffer, len);

    packet->m_packetType = RTMP_PACKET_TYPE_AUDIO; // 包类型，音频
    packet->m_nBodySize = body_size;
    packet->m_nChannel = 11; // 通道ID，随便写一个，注意：不要写的和rtmp.c(里面的m_nChannel有冲突 4301行)
    packet->m_nTimeStamp = 0; // 帧数据没有时间戳
    packet->m_hasAbsTimestamp = 0; // 一般都不用
    packet->m_headerType = RTMP_PACKET_SIZE_LARGE; // 大包的类型，如果是头信息，可以给一个小包

    // 把数据包放入队列
    if (audioCallback != nullptr)
        audioCallback(packet);

}


// TODO 音频编码工作 (通过faac来编码)
void SAudioChannel::encodeData(int8_t *data) {
    // return 返回编码后字节长度
    int len = faacEncEncode(
            audioEncoder,  // 编码器
            reinterpret_cast<int32_t *>(data), // 数据
            inputSamples, // 样本数
            buffer, // 缓冲区 (接收成果的输出缓冲区)
            maxOutputBytes // 最大输出字节
    );


    if (len <= 0) {
        return;
    }

    auto *packet = new RTMPPacket;

    int body_size = 2 + len;

    RTMPPacket_Alloc(packet, body_size);

    if (mChannels == 1) {
        // AAC，44100采样率，
        packet->m_body[0] = 0xAF; // 双声道
    } else {
        packet->m_body[0] = 0xAE; // 单声道
    }

    packet->m_body[1] = 0x01;

    // 将数据copy到pack中
    memcpy(&packet->m_body[2], buffer, len);

    packet->m_packetType = RTMP_PACKET_TYPE_AUDIO; // 包类型，音频
    packet->m_nBodySize = body_size;
    packet->m_nChannel = 11; // 通道ID，随便写一个，注意：不要写的和rtmp.c(里面的m_nChannel有冲突 4301行)
    packet->m_nTimeStamp = -1; // 帧数据有时间戳
    packet->m_hasAbsTimestamp = 0; // 一般都不用
    packet->m_headerType = RTMP_PACKET_SIZE_LARGE; // 大包的类型，如果是头信息，可以给一个小包

    // 把数据包放入队列
    if (audioCallback != nullptr)
        audioCallback(packet);

}

void SAudioChannel::setAudioCallback(AudioCallback a) {
    this->audioCallback = a;
}

SAudioChannel::SAudioChannel() {
    pthread_mutex_init(&mutex, nullptr);
    LOG_D("AudioChannel 构造函数")
}

